<!-- 可放置 merge 目录下的通用 tag -->

<!-- 头部 -->
<learn-header>
  <style scoped>
  :scope{display: block; box-shadow: 0 0 10px #ccc; overflow: hidden; margin-bottom: 40px; padding-top: 10px; }
  img{display: inline-block; width: 70px; padding: 10px; }
  </style>
  <img src="http://riotjs.com/img/logo/riot240x.png">
  <yield/>
</learn-header>

<!-- 侧栏 -->
<learn-nav>
  <style scoped>
  :scope{ display: inline-block; width: 20%; }
  li{list-style-type: none; margin-bottom: 10px; font-size: 16px; }
  a{ color: #268BD2; } .active a{ color: #f04; text-decoration: none; }
  </style>
  <ul>
    <!-- opts == tag.opts (放置调用tag传递的参数) -->
    <!-- each 建议使用 item, index in items 这种格式 -->
    <li each="{nav in opts.items}"
        class="{active: nav.action == App.route.action}">
      <a href="learn-riot-app/{nav.action}">
        {nav.text} <span if="{nav.action == App.route.action}">🐶</span>
      </a>
    </li>
  </ul>
</learn-nav>

<!-- 锚点跳转 -->
<anchor>

  <style scoped>
  :scope{}a{color: #268BD2}
  </style>

  <a href="javascript:;" onclick="{ev.anchor}"><yield/></a>

  <script>
    var tag = this;
    tag.ev = {
      anchor: function(){
        var anchor = document.querySelector('#'+opts.to);
        window.scrollTo(0, anchor.offsetTop);
      }
    };
    tag.fn = {};
    tag.on('mount', function(){});
  </script>

</anchor>


<section-template>
  <h2>模版语法</h2>
  <p>
    模版中使用 \{ 表达式 \} 来渲染 js表达式
    <iframe height='471' scrolling='no' title='Pip+Riot Demo' src='//codepen.io/linyupark/embed/GWmQVx/?height=471&theme-id=dark&default-tab=html,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='http://codepen.io/linyupark/pen/GWmQVx/'>Pip+Riot Demo</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
  </p>
  <h3>条件渲染 if / show / hide</h3>
  <p style="padding: 0">
    <ul>
      <li>show – 当值为真时用 style="display: ''" 显示元素</li>
      <li>hide – 当值为真时用 style="display: none" 隐藏元素</li>
      <li>if – 在 document 中添加 (真值) 或删除 (假值) 元素</li>
    </ul>
    <span style="color: #91CCEC; font-size: 12px; ">
      💡 if 如果使用在 tag 上会触发 mount
    </span>
    <br>
    <iframe height='480' scrolling='no' title='Pip+Riot Demo' src='//codepen.io/linyupark/embed/gmWeWB/?height=480&theme-id=dark&default-tab=html,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 85%;'>See the Pen <a href='http://codepen.io/linyupark/pen/gmWeWB/'>Pip+Riot Demo</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
  </p>
  <h3>循环对象处理</h3>
  <p>
    常见的一种场景，我们获取文章列表，然后可以点击其中的某个进行操作
    <iframe height='520' scrolling='no' title='Pip+Riot Demo' src='//codepen.io/linyupark/embed/EWmEbm/?height=520&theme-id=dark&default-tab=html,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='http://codepen.io/linyupark/pen/EWmEbm/'>Pip+Riot Demo</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
  </p>
  <h3>virtual 标签</h3>
  <p>
    在一些循环场景，需要循环多个不包含根标签的元素，可以使用virtual
    <iframe height='265' scrolling='no' title='Pip+Riot Demo' src='//codepen.io/linyupark/embed/dvWmee/?height=265&theme-id=dark&default-tab=html,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='http://codepen.io/linyupark/pen/dvWmee/'>Pip+Riot Demo</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
  </p>
  <h3>使用现有的HTML标签载入自定义tag</h3>
  <p>
    在一些根据变量加载不同标签的情况下可以使用 data-is 属性来挂载标签（缺点：传参需要做判断）
    <iframe height='269' scrolling='no' title='Pip+Riot Demo' src='//codepen.io/linyupark/embed/EWmERX/?height=269&theme-id=dark&default-tab=html,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='http://codepen.io/linyupark/pen/EWmERX/'>Pip+Riot Demo</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
  </p>
  <h3>yield 标签</h3>
  <p>
    可以理解为一些填空区域
    <iframe height='276' scrolling='no' title='Pip+Riot Demo' src='//codepen.io/linyupark/embed/QpgWej/?height=276&theme-id=dark&default-tab=html,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='http://codepen.io/linyupark/pen/QpgWej/'>Pip+Riot Demo</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
    yield 内可以放任何形式的内容，包括 tag，但在这个区域内 tag 的作用域会变为 yield的来源 tag：
    <iframe height='432' scrolling='no' title='Pip+Riot Demo' src='//codepen.io/linyupark/embed/xqrbVj/?height=432&theme-id=dark&default-tab=html,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='http://codepen.io/linyupark/pen/xqrbVj/'>Pip+Riot Demo</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
  </p>
</section-template>


<section-observable>
  <h2>事件监听模式 (Observable)</h2>
  <p>
    本框架将 Riot 里的 observable 函数抽取了出来，
    变名为 emitter，想要将一个对象变为可自定义事件监听，看个 🌰
    <iframe height='600' scrolling='no' title='evWJPL' src='//codepen.io/linyupark/embed/evWJPL/?height=600&theme-id=dark&default-tab=js,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='http://codepen.io/linyupark/pen/evWJPL/'>evWJPL</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
  </p>

  <p>
    本框架自动将所有挂载的 tag 都赋予了这种特性，因此我们可以方便的在各 tag 之间通讯数据
    <iframe height='601' scrolling='no' title='mWmPKq' src='//codepen.io/linyupark/embed/mWmPKq/?height=601&theme-id=dark&default-tab=html&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='http://codepen.io/linyupark/pen/mWmPKq/'>mWmPKq</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
    <br>
    <demo-observable/>
  </p>

</section-observable>



<section-reserved-words>

  <h2>保留关键字</h2>
  <p>
    Riot 关键字有:
    opts,
    <anchor to="parent">parent</anchor>,
    <anchor to="tags">tags</anchor>,
    <anchor to="root">root</anchor>,
    <anchor to="refs">refs</anchor>,
    update,
    unmount,
    <a href="learn-riot-app/observable">
    on,
    off,
    once 跟
    emit </a><br>
    <span style="color: #91CCEC; font-size: 12px; ">
      💡官方用的是one, trigger 为了语意更标准化，本框架使用 once 跟 emit
    </span><br>
    框架追加: App, Store, State
  </p>

  <h3>opts</h3>
  <p>
    用于组件之间的数据传输，初始化参数设定等
    <iframe height='420' scrolling='no' title='Pip+Riot Demo' src='//codepen.io/linyupark/embed/ZeeyyL/?height=420&theme-id=dark&default-tab=html,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='http://codepen.io/linyupark/pen/ZeeyyL/'>Pip+Riot Demo</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
  </p>

  <h3 id="parent">parent</h3>
  <p>
    情况一： 子 tag 访问父 tag 的属性或者方法
    <iframe height='265' scrolling='no' title='Pip+Riot Demo' src='//codepen.io/linyupark/embed/WppZQK/?height=265&theme-id=dark&default-tab=html,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='http://codepen.io/linyupark/pen/WppZQK/'>Pip+Riot Demo</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
  </p>
  <p>
    情况二：循环列表中子元素调用函数或者属性
    <iframe height='300' scrolling='no' title='Pip+Riot Demo' src='//codepen.io/linyupark/embed/EWWwga/?height=300&theme-id=dark&default-tab=html,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='http://codepen.io/linyupark/pen/EWWwga/'>Pip+Riot Demo</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
  </p>

  <h3 id="tags">tags</h3>
  <p>
    当前 tag 内嵌入的其他 tag 都会放置到 tags[] 中，如果一样的 tag 多次嵌入则放入 tags[嵌入tag名称][]
    <iframe height='350' scrolling='no' title='Pip+Riot Demo' src='//codepen.io/linyupark/embed/PppJJR/?height=350&theme-id=dark&default-tab=html,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='http://codepen.io/linyupark/pen/PppJJR/'>Pip+Riot Demo</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
  </p>

  <h3 id="root">root</h3>
  <p>
    返回当前tag对应的 html dom 元素
  </p>

  <h3 id="refs">refs</h3>
  <p>
    tag.refs 可以对应到模版中 元素属性为 ref 的 dom
    <iframe height='265' scrolling='no' title='Pip+Riot Demo' src='//codepen.io/linyupark/embed/zZZEmq/?height=265&theme-id=dark&default-tab=html,result&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 100%;'>See the Pen <a href='http://codepen.io/linyupark/pen/zZZEmq/'>Pip+Riot Demo</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
  </p>

  <h3>update</h3>
  <p>
    tag.update() 手动刷新tag以及tag内嵌套的view <br>
    tag.update(\{xx:xxNewValue\}) 指定刷新某值（性能较好）<br>
    官方说明 <a target="_blank" href="http://riotjs.com/api/#updating">http://riotjs.com/api/#updating</a>
  </p>

  <h3>unmount</h3>
  <p>
    卸载某个挂载好的tag，如果带上 tag.unmount(<strong>true</strong>) 会将挂载点也一起删除。<br>
    官方说明 <a target="_blank" href="http://riotjs.com/api/#unmounting">http://riotjs.com/api/#unmounting</a>
  </p>
</section-reserved-words>



<section-mixin-app>
  <h2>组件间共享数据 （Mixin）</h2>
  <p>
    官方对 mixin 的中文说明：
    <a href="http://riotjs.com/v2/zh/guide/#mixin" target="_blank">http://riotjs.com/v2/zh/guide/#mixin</a>
    <br>
    本框架在 main.js 跟 lib/store.js 中使用了 mixin <br>
    作用域：tag.App(所有), tag.Store, tag.State(按需)
  </p>
  <h3>tag.App</h3>
  <p style="padding: 0">
    请查看 console 打印信息：
    <ul>
      <li><b>cgf:</b>
        项目配置信息；</li>
      <li><b>api:</b>
        存放的是项目中需要跟服务器接口的唯一函数 (根据项目需要 main.js 中修改)，xhr 用 pip.xhr 可实现；</li>
      <li><b>log:</b>
        在debug模式下显示打印记录 tag.App.log('....')；</li>
      <li><b>route:</b>
        当前页面的路由信息，page/action?query (本页对应的就是 {App.route.page}/{App.route.action}?\{\})；</li>
    </ul>
    如果项目有其他需要也可以往里继续添加，但因为是全局有效，尽量只放一些核心的内容。
  </p>
  <h3>tag.Store {'&'} tag.State</h3>
  <p>
    当 main.js 中加载了 redux.js 以及 store.js 就可以在 tag 中用 tag.mixin('redux') 来激活使用。
    <br>
    <button type="button" onclick="{ev.active}">激活</button>
    <br>
    <span if="{Store}">
      这个用户的角色信息<b>({State.account.role})</b>
      来自 \{tag.State.account.role\} <br>
      <button type="button" onclick="{ev.changeRole}">{State.account.login?'变guest':'变admin'}</button>
    </span>
    <br><br>

    <b>为什么 UI 组件式的框架需要 Redux加持？</b>
    <br>
    在项目看来数据应该是整体的，划分成几个逻辑的对象，如user,post等
    <br>
    但 UI 组件开发使用到的这些数据有时候是零碎的，虽然我们有 emitter 跟 opts 可以做到组件数据的互通，但在一些复杂的交互跟数据库有互动的数据上，要保持视图跟数据的统一引入 Redux 就显得很重要。

    <br><br>

    更多Redux相关的知识请查阅：<a href="http://cn.redux.js.org/index.html" target="_blank">http://cn.redux.js.org/index.html</a>
  </p>
  <script>
    var tag = this;
    tag.ev = {
      changeRole: function(){
        if(tag.State.account.login)
          tag.Store.emit('account.logout');
        else
          tag.Store.emit('account.login', {
            role: 'admin'
          });
      },
      active: function(){
        if(!tag.Store){
          tag.mixin('redux');
        }
      }
    };
    tag.fn = {};
    tag.on('mount', function(){
      console.log('tag.App:', tag.App);
    });
  </script>
</section-mixin-app>


<section-howto>
  <h2>UI组件式开发思路 🤔 </h2>
  <p>
    前端开发的终极目的？（数据或内容如何展现到用户面前）
  </p>

  <h3>从UI的角度拆分逻辑</h3>
  <p style="padding: 0">
    <img width="100%" src="http://cdn3.infoqstatic.com/statics_s1_20170228-0434_4/resource/articles/subversion-front-end-ui-development-framework-react/zh/resources/1211023.png">
    <br>
    具体我们要去做的就是将几个细节的UI组件开发好，最后拼合成下面这样形态的完整页面。
    <br>
    <iframe height='216' scrolling='no' title='Pip+Riot Demo' src='//codepen.io/linyupark/embed/NpjYmq/?height=216&theme-id=dark&default-tab=html&embed-version=2' frameborder='no' allowtransparency='true' allowfullscreen='true' style='width: 85%;'>See the Pen <a href='http://codepen.io/linyupark/pen/NpjYmq/'>Pip+Riot Demo</a> by Yu (<a href='http://codepen.io/linyupark'>@linyupark</a>) on <a href='http://codepen.io'>CodePen</a>.
    </iframe>
    <br>
    对于评论界面而言，整个UI是一个通过小组件构成的大组件，每个组件只关心自己部分的逻辑，彼此独立。
    <br>
    一个组件应该具有如下特征:
    <ul>
      <li>
        可组合：一个组件易于和其它组件一起使用，或者嵌套在另一个组件内部；
      </li>
      <li>
        可重用：每个组件都是具有独立功能的，它可以被使用在多个UI场景；
      </li>
      <li>
        可维护：每个小的组件仅仅包含自身的逻辑，更容易被理解和维护；
      </li>
      <li>
        可测试：因为每个组件都是独立的，那么对于各个组件分别测试显然要比对于整个UI进行测试容易的多。
      </li>
    </ul>
    <br>
    本框架对组件开发的要求规范可参考：
    <a href="https://git.oschina.net/linyupark/riot-component" target="_blank">https://git.oschina.net/linyupark/riot-component</a>
  </p>
</section-howto>




<!-- 举例实际演示 -->
<demo-observable-counter>
  <span>{n}</span>
  <script>
  var tag = this;
  tag.n = 0;
  tag.on('+n', function(n){
    // 接受到指令后就自+n
    tag.update({n: tag.n + Number(n)});
  });
  </script>
</demo-observable-counter>

<demo-observable>

  <demo-observable-counter ref="c" />
  <input type="number" ref="n" />
  <button onclick={ev.addNumber}>add</button>

  <script>
  var tag = this;
  tag.ev = {
    addNumber: function(){
      // 这里也可以用 tag.tags.counter 来拿到 tag counter，用 ref 更好。
      // 这样就触发了 +n 事件，并将 input 里的数值传递过去
      tag.refs.c.emit('+n', tag.refs.n.value || 1);
    }
  }
  </script>

</demo-observable>




<!-- user 业务主 tag -->
<page-learn-riot-app>

  <style scoped>
  :scope{ font-size: 14px; line-height: 150%; }
  h1{ font-size: 24px; display: inline-block; vertical-align: top; padding-bottom: 10px; width: 80%; }
  section{ display: inline-block; width: 70%; min-height: 80%; vertical-align: top; padding-bottom: 100px; }
  section p{ font-size: 16px; color: #444; padding-right: 15%; line-height: 180%; padding-bottom: 50px; }
  section p a{ color: #268BD2; }
  .scroll-up{position: fixed; right: 20px; bottom: 20px; cursor: pointer; font-size: 20px; }
  h3{ font-size: 20px; }
  h3{ font-size: 18px; }
  </style>

  <learn-header>
    <h1>学习使用框架</h1>
  </learn-header>

  <learn-nav items="{navList}"/>

  <section>

    <!-- 首页 -->
    <virtual if={App.route.action==''}>
      <p>
        <iframe width="125%" height="2560" scrolling="no" src="http://codepen.io/linyupark/post/pip-riot-howto-write" frameborder="0"></iframe>
      </p>
    </virtual>

    <!-- 其他自动挂载页 -->
    <div if={App.route.action!=''} data-is="section-{App.route.action}"></div>

  </section>

  <div class="scroll-up" onclick="{ev.scrollUp}">⬆️️</div>

  <script>
    var tag = this;
    tag.mixin('redux');
    tag.navList = [
      {action: '', text: 'tag规范概述'},
      {action: 'reserved-words', text: '保留关键字'},
      {action: 'observable', text: '事件监听模式'},
      {action: 'mixin-app', text: '组件间共享数据'},
      {action: 'template', text: '模版语法'},
      {action: 'howto', text: 'UI组件式开发思路'}
    ];
    tag.ev = {
      scrollUp: function(){
        window.scrollTo(0,0);
      }
    };
    tag.fn = {};
  </script>

</page-learn-riot-app>
